#include "device/Display.h"


bool Display::read(word_t start_addr, size_t length, uint8_t* buffer) {
	if (start_addr >= VCTL_BASE && start_addr < VCTL_BASE + VCTL_SIZE) {
		uint32_t offset = start_addr - VCTL_BASE;
		assert(offset == 0 || offset == 4);
		memcpy(buffer, (uint8_t*)vctl + offset, length);
		return true;
	} else if (start_addr >= VMEM_BASE && start_addr < VMEM_BASE + VMEM_SIZE) {
		uint32_t offset = start_addr - VMEM_BASE;
		memcpy(buffer, vmem + offset, length);
		return true;
	}
    return false;
}

bool Display::write(word_t start_addr, size_t length, const uint8_t* buffer) {
	if (start_addr >= VCTL_BASE && start_addr < VCTL_BASE + VCTL_SIZE) {
		uint32_t offset = start_addr - VCTL_BASE;
		assert(offset == 0 || offset == 4);
		memcpy((uint8_t*)vctl + offset, buffer, length);
		return true;
	} else if (start_addr >= VMEM_BASE && start_addr < VMEM_BASE + VMEM_SIZE) {
		uint32_t offset = start_addr - VMEM_BASE;
		memcpy(vmem + offset, buffer, length);
		return true;
	}
    return false;
}

void Display::update() {
    if (vctl[1]) {
        update_screen();
        vctl[1] = 0;
    }
}

Display::Display() {
    vmem = new uint8_t[VMEM_SIZE]; ///???
    vctl[0] = (SCREEN_W << 16) | SCREEN_H;    ///???

    // init screen
	window = NULL;
	char title[128];
	sprintf(title, "%s-NPC", "RISCV");
	SDL_Init(SDL_INIT_VIDEO);
	SDL_CreateWindowAndRenderer(
			SCREEN_W,
			SCREEN_H,
			0, &window, &renderer);
	SDL_SetWindowTitle(window, title);
	texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
			SDL_TEXTUREACCESS_STATIC, SCREEN_W, SCREEN_H);
}

void Display::update_screen() {
	SDL_UpdateTexture(texture, NULL, vmem, SCREEN_W * sizeof(uint32_t));
	SDL_RenderClear(renderer);
	SDL_RenderCopy(renderer, texture, NULL, NULL);
	SDL_RenderPresent(renderer);
}

Display::~Display() {
	SDL_DestroyTexture(texture);
	SDL_DestroyRenderer(renderer);
	SDL_DestroyWindow(window);
    delete[] vmem;
}
